
#import "ContentsController.h"
#import "ChapterViewController.h"
#import "Chapter.h"
#import "RecipeTableViewCell.h"


//////////////////////////////////////////////////////////////
//  Description
//     object-->responder-->viewController-->tableViewController
//
//  Instance methods of the ContentsController:
//     (NSFetchedResultsController *) fetchedResultsController;
//
//  Overrite UIViewController methods:
//     -(void) viewDidLoad;
//     -(void) shouldAutorotateToInterfaceOrientation(UIInterfaceOrientation *)
//
//  RecipeAddDelegate interface:
//     -(void) recipeAddViewController:didAddRecipe:
//
//  TableView DataSource delegate interface:
//     -(NSInteger) numberOfSectionsInTableView;
//     -(NSInteger) tableView:numberOfRowsInSection:(NSInteger) section;
//     -(UITableViewCell *) tableView:cellForRowAtIndexPath:;
//
//  TableView Delegate interface:
//     -(void) tableView:didSelectRowAtIndexPath
//
//  TableView Edit interface:
//     -(void) tableView:commitEditingStyle:forRowAtIndexPath:
//
//  FetchedResultsController Delegate:
//     -(void) controllerWillChangeContent:(NSFetchedResultsController *)
//     -(void) controllerDidChangeContent:(NSFetchedResultsController *)
//     -(void) controllerDidChangeObject:atIndexPath:forChangeType:newIndexPath:     
//     -(void) controllerDidChangeSection:atIndex:forChangeType:
//     
//  Implementation ContendsController Private Methods
//     -(void) add:(id)
//     -(void) goToChapter:atIndexPath:
//     -(void) configureCell:atIndexPath:
/////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////
//  obj->repsonder->viewController->tableViewController
/////////////////////////////////////////////////////////////

/////////////////////////////////////////////
// Contents instance methods
// 1) goToChapter:animated:
// 2) configureCell:atIndexPath:
/////////////////////////////////////////////

@interface ContentsController(private) 

-(void) add: (id)sender;

-(void) recipeAddViewController:(RecipeAddViewController *)recipeAddViewController 
                   didAddRecipe:(Chapter *)chapter;

-(void)goToChapter:(Chapter *) chapter 
          animated:(BOOL) animated;

-(void)configureCell:(RecipeTableViewCell *)cell 
         atIndexPath:(NSIndexPath *)indexPath;


@end



/////////////////////////////////////////////
//  ConentsController Implementation
//     is viewController/tableViewController
//     has view & tableView
// 
//  obj->respender->viewController->tableViewController
//  Implementation
//  : UITableViewController<delegate protocol>
/////////////////////////////////////////////
@implementation ContentsController

@synthesize managedObjectContext;
@synthesize fetchedResultsController;



/////////////////////////////////////////////
//  Instance Methods defined in the class
/////////////////////////////////////////////

#pragma mark -
#pragma mark Fetched results controller
/////////////////////////////////////////////
//  Getters for core data
/////////////////////////////////////////////
-(NSFetchedResultsController *) fetchedResultsController {

   //NSLog(@"*************** fetchedResultsController");
   /**
    * Set up the fetched results controller if needed.
    * if already setup returns
    */
   if( self->fetchedResultsController ) { return self->fetchedResultsController; }
  
 
   // Create the fetch request for the entity.
   NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

   // Edit the entity name as appropriate.
   NSEntityDescription *entity = [NSEntityDescription entityForName:@"Recipe" 
                                             inManagedObjectContext:managedObjectContext];

   [fetchRequest setEntity:entity];
   
   // Edit the sort key as appropriate.
   NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" 
                                                                  ascending:YES];

   NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:
                                                          sortDescriptor, 
                                                          nil];
   
   [fetchRequest setSortDescriptors:sortDescriptors];
   
   // Edit the section name key path and cache name if appropriate.
   // nil for section name key path means "no sections".
   NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
                                     initWithFetchRequest:fetchRequest 
                                     managedObjectContext:managedObjectContext 
                                       sectionNameKeyPath:nil 
                                                cacheName:@"Root"];

   aFetchedResultsController.delegate = self;
   self.fetchedResultsController = aFetchedResultsController;
   
   [aFetchedResultsController release];
   [fetchRequest release];
   [sortDescriptor release];
   [sortDescriptors release];
     
   return fetchedResultsController;
}  


#pragma mark -
#pragma mark UIViewController overrides
/**
 * Override UIViewController instance methods:
 * *) viewDidLoad: implementated
 * *) loadView
 * *) viewDidAppear
 * *) viewWillAppear
 * *) viewWillDisappear
 * *) viewDidUnload
 * *) shouldAutorotateToIntfaceOrientation: implemented
 */
/////////////////////////////////////////////
//  @override
-(void)viewDidLoad {
 
  /**
   * Configure the navigation bar.
   * Add buttonItem
   */
  [self setTitle: @"Triangle"];

  /**
   * bckong
   * Get a ref of the navigationItem from the viewController
   */
  UINavigationItem *navigationItem = [self navigationItem];
  [navigationItem setLeftBarButtonItem: [self editButtonItem]];
  
  UIBarButtonItem *addButtonItem = [[UIBarButtonItem alloc] 
                                       initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 
                                                            target:self 
                                                            action:@selector(add:)];

  [navigationItem setRightBarButtonItem: addButtonItem];
  [addButtonItem release];
 

  /* Get tableview ref and set the table view's row height */
  UITableView *tableView = [self tableView];
  [tableView setRowHeight: 44.0];
	
  /**
   * Check core data fectedResultsController error
   */
  NSError *error = nil;
  if( [[self fetchedResultsController] performFetch: &error]==nil ) {
    /*
     Replace this implementation with code to handle the error appropriately.
     
     abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
     */
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
     abort();
  }  
  
}


/////////////////////////////////////////////
// auto rotate to interface orientation
/////////////////////////////////////////////
// @override
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

  //NSLog(@"------> ContentViewController:shouldAutorotateToInterfaceOrientation");
  // Support all orientations except upside down
  return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

#pragma mark -
#pragma mark Memory management
/////////////////////////////////////////////
-(void)dealloc {
  [fetchedResultsController release];
  [managedObjectContext release];
  [super dealloc];
}



#pragma mark -
#pragma mark Table view methods

/////////////////////////////////////////////
//  DataSource Protocol Implementation
//    --- (int) numberOfSectionsInTableView:
//    --- (int) tableView:numberOfRowsInSection:
//    --- (UITableViewCell *) tableView:cellForRowAtIndexPath:
/////////////////////////////////////////////
-(NSInteger) numberOfSectionsInTableView:(UITableView *) tableView {

  NSInteger count = [[fetchedResultsController sections] count];
  
  if (count == 0) {
    count = 1;
  }
  
  return count;
}

/////////////////////////////////////////////
-(NSInteger)tableView:(UITableView *)tableView 
numberOfRowsInSection:(NSInteger)section {
  NSInteger numberOfRows = 0;
  
  if ([[fetchedResultsController sections] count] > 0) {
    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    numberOfRows = [sectionInfo numberOfObjects];
  }
  
  return numberOfRows;
}

/////////////////////////////////////////////
-(UITableViewCell *)tableView:(UITableView *) tableView 
        cellForRowAtIndexPath:(NSIndexPath *) indexPath {

  /**
   * Dequeue or if necessary create a ChapterTableViewCell, 
   * then set its chapter to the chapter for the current row.
   */
  static NSString *ChapterCellID = @"ChapterCellID";
  
  RecipeTableViewCell *chapterCell = (RecipeTableViewCell *)[tableView dequeueReusableCellWithIdentifier:ChapterCellID];
  if( chapterCell == nil ) {
    chapterCell = [[[RecipeTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                              reuseIdentifier:ChapterCellID] autorelease];

    [chapterCell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
  }
  
  [self configureCell:chapterCell 
          atIndexPath:indexPath];
  
  return chapterCell;

}



/////////////////////////////////////////////
// UItableView delegate
// methods:
//   ---(void)tableView:didSelectRowAtIndexPath: implemented
//   ---tableView:viewForFooterInSection: not implemented
//   ---tableView:heightForRowAtIndexPath: not implmented
/////////////////////////////////////////////
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

  /**
   * get a chapter object
   */
  Chapter *chapter = (Chapter *)[fetchedResultsController objectAtIndexPath:indexPath];
  
  [self goToChapter:chapter animated:YES];
}




///////////////////////////////////////////////
// Override to support editing the table view.
//////////////////////////////////////////////
-(void)  tableView:(UITableView *)tableView 
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle 
 forRowAtIndexPath:(NSIndexPath *)indexPath {

  if (editingStyle == UITableViewCellEditingStyleDelete) {
    // Delete the managed object for the given index path
    NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
    [context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
    
    // Save the context.
    NSError *error;
    if ([context save: &error]==nil) {
      /*
       Replace this implementation with code to handle the error appropriately.
       
       abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
       */
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
      abort();
    }
  }   
}




/**
 * Delegate methods of NSFetchedResultsController 
 * to respond to additions, removals and so on.
 */
/////////////////////////////////////////////
// Delegate methods of NSFetchedResultsController
// Results change handler
// methods:
//    ---(void) controllerWillChangeContent: implemented
//    ---(void) controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: implementated
//    ---(void) controllerDidChangeContent: implemented
/////////////////////////////////////////////
-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
  //NSLog(@"---------> controllerViewChangeContent:");
  // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
  [self.tableView beginUpdates];
}

/////////////////////////////////////////////
-(void)controller:(NSFetchedResultsController *)controller 
  didChangeObject:(id)anObject 
      atIndexPath:(NSIndexPath *)indexPath 
    forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath {

  UITableView *tableView = self.tableView;
  
  switch(type) {
    case NSFetchedResultsChangeInsert:
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;
      
    case NSFetchedResultsChangeDelete:
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;
      
    case NSFetchedResultsChangeUpdate:
      [self configureCell:(RecipeTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
      break;
      
    case NSFetchedResultsChangeMove:
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;
  }
}

/////////////////////////////////////////////
-(void)controller:(NSFetchedResultsController *)controller 
 didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo 
          atIndex:(NSUInteger)sectionIndex 
    forChangeType:(NSFetchedResultsChangeType)type {

  switch( type ) {
    case NSFetchedResultsChangeInsert:
      [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
      break;
      
    case NSFetchedResultsChangeDelete:
      [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
      break;
  }
}

/////////////////////////////////////////////
-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
  // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
  [self.tableView endUpdates];
}

@end





/////////////////////////////////////////////////////////////
//  Implementation ContentsController Private Methods
/////////////////////////////////////////////////////////////
@implementation ContentsController(private)

#pragma mark -
#pragma mark Recipe support
/////////////////////////////////////////////
-(void)add: (id)sender {

  //NSLog(@"-----> add");
  /**
   * To add a new recipe, create a RecipeAddViewController.  
   * Present it as a modal view so that the user's focus is on the 
   * task of adding the recipe; wrap the controller in 
   * a navigation controller to provide a navigation bar for 
   * the Done and Save buttons (added by the RecipeAddViewController 
   * in its viewDidLoad method).
   */
  RecipeAddViewController *addController = [[RecipeAddViewController alloc] initWithNibName:@"RecipeAddView" 
                                                                                     bundle:nil];

  addController.delegate = self;
  
  Chapter *newChapter = [NSEntityDescription insertNewObjectForEntityForName:@"Recipe" 
                                                      inManagedObjectContext:self.managedObjectContext];

  addController.recipe = newChapter;

  UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:addController];
  [self presentModalViewController:navigationController animated:YES];
  
  [navigationController release];
  [addController release];
}


/////////////////////////////////////////////
//  RecipeAddDelegate
/////////////////////////////////////////////
-(void)recipeAddViewController:(RecipeAddViewController *)recipeAddViewController 
                  didAddRecipe:(Chapter *)chapter {

  NSLog(@"----->contentsController: recipeAddViewController");
  if( chapter ) {    
     // Show the recipe in a new view controller
     [self goToChapter:chapter 
              animated:NO];
  }
  
  // Dismiss the modal add recipe view controller
  [self dismissModalViewControllerAnimated:YES];

}


/////////////////////////////////////////////////////////////
-(void)goToChapter:(Chapter *) chapter 
          animated:(BOOL) animated {

  /**
   * Create the chapter view controller from scratch, 
   * set the chapter, then push it.
   */
  ChapterViewController *chapterViewController = [[ChapterViewController alloc] 
                                                           initWithStyle:UITableViewStyleGrouped];
  [chapterViewController setChapter:chapter];
  
  /**
   * push the detailed Controller to 
   * the viewController array in the navController
   */
  [self.navigationController pushViewController:chapterViewController 
                                       animated:animated];
  [chapterViewController release];
}


/////////////////////////////////////////////
// Private methods used by dataSource Protocol
/////////////////////////////////////////////
-(void)configureCell:(RecipeTableViewCell *)cell 
         atIndexPath:(NSIndexPath *)indexPath {

  // Configure the cell
  Chapter *chapter = (Chapter *)[fetchedResultsController objectAtIndexPath:indexPath];
  cell.recipe = chapter;

}

@end

